package com.codeavatar.hardwaretester.lib;

import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanResult;
import android.bluetooth.le.ScanSettings;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;

import androidx.annotation.Nullable;

import com.codeavatar.catools.helper.CaHardwareHelper;
import com.codeavatar.catools.helper.CaLogHelper;
import com.codeavatar.catools.helper.CaReceiverHelper;
import com.codeavatar.catools.helper.CaToastHelper;
import com.codeavatar.catools.tool.CaConvertTool;
import com.codeavatar.hardwaretester.model.BluetoothCharacteristicModel;
import com.codeavatar.hardwaretester.model.BluetoothConnectModel;
import com.codeavatar.hardwaretester.model.BluetoothDeviceModel;
import com.codeavatar.hardwaretester.model.BluetoothServiceModel;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

/**
 * +----------------------------------------------------------------------
 * | @Author: codeavatar   @Year：2022
 * +----------------------------------------------------------------------
 * | @Email: codeavatar@aliyun.com
 * +----------------------------------------------------------------------
 **/
//蓝牙（低功耗蓝牙，传统篮牙） 【注意：权限自定义限制】
//传统蓝牙适用于电池使用强度较大的操作,另一个则相反
//低功耗蓝牙(蓝牙4.0+)
@SuppressLint("MissingPermission")
public class BluetoothLib {

    private final String TAG = this.getClass().getSimpleName();

    //设置广播
    public static final String ACTION_APP_BLE = "codeavatar.action.lib.ble";
    public static final String ACTION_APP_BLE_CHANGE = "codeavatar.action.lib.ble.change";
    public static final String PERMISSION_APP_BLUETOOTH = "com.codeavatar.hardwaretester.APP_BLUETOOTH";
    //广播类型
    public static final String BROADCAST_BLE_FOUND = "ble_found_device";
    public static final String BROADCAST_BLE_CONNECT = "ble_connect_device";
    public static final String BROADCAST_BLE_DISCONNECT = "ble_disconnect_device";

    private Context context;
    private String bleDeviceId;
    private UUID bleServiceUuid;
    private UUID bleCharacteristicUuid;

    private boolean isConnecting = false;//蓝牙状态
    private boolean isDiscovering = false;//搜索状态
    private BluetoothAdapter bluetoothAdapter;
    private BluetoothLeScanner bluetoothLeScanner;
    private List<BluetoothDeviceModel> bluetoothDeviceModelList;
    private Map<String,ScanResult> scanResultMap;
    private BluetoothGatt bluetoothGatt; //中央服务
    private BluetoothGattService bluetoothGattService;//服务
    private BluetoothGattCharacteristic bluetoothGattCharacteristic;//特征
    private CaReceiverHelper caReceiverHelper;

    //绑程操作
    private HandlerThread handlerThread;
    private Handler handler;

    //++++++++++++++++++++++++++++++++++++++
    //++ 外部方法
    //++++++++++++++++++++++++++++++++++++++

    public BluetoothLib(Context context){
        this.context = context;
    }

    public boolean isConnecting() {
        return isConnecting;
    }

    public boolean isDiscovering() {
        return isDiscovering;
    }

    //初始化
    public void doInit(String bleDeviceId,UUID bleServiceUuid,UUID bleCharacteristicUuid){
        //固定设置(MAC，服务UUID，特征UUID)
        this.bleDeviceId = bleDeviceId;
        this.bleServiceUuid = bleServiceUuid;
        this.bleCharacteristicUuid = bleCharacteristicUuid;
        //线程初始化
        handlerThread = new HandlerThread(TAG+"-handler");
        handlerThread.start();
        handler = new Handler(handlerThread.getLooper());
        //初始变量
        bluetoothDeviceModelList = new ArrayList<>();
        this.initRegisterReveiver();
        //开启适配器
        //(方式一)
        BluetoothManager blutoothManager=(BluetoothManager) this.context.getSystemService(Context.BLUETOOTH_SERVICE);
        bluetoothAdapter = blutoothManager.getAdapter();
//        //(方式二)
//        bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        if(this.isHasAdapter()){
            if(!bluetoothAdapter.isEnabled()){
                bluetoothAdapter.enable();
            }
            bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner();
        }
    }
    //搜索外围设备
    public void doDiscovery(){
        if(!this.isHasAdapter()) return;

        if(!CaHardwareHelper.init().isLocationOpen(this.context)){
            CaToastHelper.toast(this.context,"请打开定位功能！");
            return;
        }
        bluetoothDeviceModelList.clear();
        Set<BluetoothDevice> boundDevices = bluetoothAdapter.getBondedDevices();
        if(boundDevices.size()>0){
            for (BluetoothDevice device : boundDevices){
                BluetoothDeviceModel deviceModel = new BluetoothDeviceModel(device.getName(),device.getAddress());
                deviceModel.setBluetoothDevice(device);
                bluetoothDeviceModelList.add(deviceModel);
            }
            CaLogHelper.info(TAG,"【doDiscovery】蓝牙获取绑定的外围设备...");
        }else {
            if(null != bluetoothLeScanner){
                if(null == scanResultMap){
                    scanResultMap = new HashMap<>();
                }else{
                    scanResultMap.clear();
                }
                bluetoothLeScanner.startScan(null,this.getScanSettings(),this.bluetoothScanCallBack);
                isDiscovering = true;
                CaLogHelper.info(TAG,"【doDiscovery】蓝牙开始搜索外围设备...");
            }
        }
    }
    //停止搜索设备
    public void doUndisconvery(){
        if(null != bluetoothLeScanner){
            bluetoothLeScanner.stopScan(this.bluetoothScanCallBack);
            isDiscovering = false;
            CaLogHelper.warn(TAG,"【doUndisconvery】蓝牙停止搜索...");
        }
    }
    //连接设备
    public void doConnect(){
        doUndisconvery();
        BluetoothDevice bluetoothDevice = bluetoothAdapter.getRemoteDevice(this.bleDeviceId);
        bluetoothGatt = bluetoothDevice.connectGatt(this.context,false,bluetoothGattCallback);
        CaLogHelper.info(TAG,"【doConnect】蓝牙开始连接...");
    }
    //断开连接
    public void doDisconnect(){
        if(null != bluetoothGatt){
            bluetoothGatt.disconnect();
            bluetoothGatt.close();
            CaLogHelper.warn(TAG,"【doDisconnect】蓝牙断开连接...");
            //断开连接
            sendBroadcastToReceiver(BROADCAST_BLE_DISCONNECT);
        }
    }
    //销毁
    public void doDestory(){
        uninitRegisterReveiver();
    }
    //写入数据
    public boolean doSendData(String hexdata, boolean isRead){
       byte[] data = CaConvertTool.hexString2Bytes(hexdata);
       return this.doSendData(data,isRead);
    }
    //写入数据
    public boolean doSendData(byte[] data,boolean isRead){
        if(null != this.bluetoothGatt && null != this.bluetoothGattCharacteristic){
            //最大20byte
            bluetoothGattCharacteristic.setValue(data);
            boolean writeResult = this.bluetoothGatt.writeCharacteristic(bluetoothGattCharacteristic);
            CaLogHelper.info(TAG,
                    String.format("【doSendData】向设备[%s]的服务[%s]特征[%s]写入[%s]%s...",
                            bleDeviceId,bleServiceUuid.toString(),bleCharacteristicUuid.toString(),
                            CaConvertTool.bytes2HexString(data),
                            (writeResult?"成功":"失败"))
            );
            if(isRead){ doReadData(); }
            return writeResult;
        }
        return false;
    }
    //读取数据
    public boolean doReadData(){
        if(null != this.bluetoothGatt){
            CaLogHelper.info(TAG, "【doReadData】蓝牙读取服务特征值...");
            boolean readResult = this.bluetoothGatt.readCharacteristic(bluetoothGattCharacteristic);
            CaLogHelper.info(TAG,
                    String.format("【doReadData】向设备[%s]的服务[%s]特征[%s]读取数据%s...",
                            bleDeviceId,bleServiceUuid.toString(),bleCharacteristicUuid.toString(),
                            (readResult?"成功":"失败"))
            );
            return readResult;
        }
        return  false;
    }
    //++++++++++++++++++++++++++++++++++++++
    //++ 内部方法
    //++++++++++++++++++++++++++++++++++++++

    private void initRegisterReveiver(){
        IntentFilter connectStateChangeFilter = new IntentFilter(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
        IntentFilter stateChangedFilter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
        this.context.registerReceiver(bluetoothDeviceReceiver,stateChangedFilter);
        this.context.registerReceiver(bluetoothDeviceReceiver,connectStateChangeFilter);
        //注意订阅者
        caReceiverHelper = new CaReceiverHelper(this.context, broadcastReceiver);
        caReceiverHelper.registerReceiver(ACTION_APP_BLE, PERMISSION_APP_BLUETOOTH);
    }

    private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            CaLogHelper.info(TAG,"[broadcastReceiver]蓝牙服务接收到来自的外部消息......");
            Bundle extras = intent.getExtras();
            if(null != extras) {
                CaLogHelper.info(extras);
                String action = extras.getString("action");
                switch (action){
                    case "":
                        break;
                    default:
                        break;
                }
            }
        }
    };

    private BroadcastReceiver bluetoothDeviceReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            CaLogHelper.info(TAG,"[bluetoothDeviceReceiver]蓝牙接受者的Action（"+action+"）...");
            if(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED.equals(action)){

            }else if(BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)){

            }
        }
    };

    private void uninitRegisterReveiver(){
        this.context.unregisterReceiver(bluetoothDeviceReceiver);
        caReceiverHelper.unregisterReceiver();
    }

    private void sendBroadcastToReceiver(Bundle extras){
        if(null == extras) extras = new Bundle();
        caReceiverHelper.sendBroadcast(ACTION_APP_BLE_CHANGE, PERMISSION_APP_BLUETOOTH,extras);
    }
    private void sendBroadcastToReceiver(String action){
        Bundle extras = new Bundle();
        extras.putString("action",action);
        sendBroadcastToReceiver(extras);
    }

    //搜索设置
    private ScanSettings getScanSettings() {
        ScanSettings.Builder builder = new ScanSettings.Builder();
        //3种模式：SCAN_MODE_LOW_POWER、SCAN_MODE_BALANCED、SCAN_MODE_LOW_LATENCY
        builder.setScanMode(ScanSettings.SCAN_MODE_BALANCED);
        //芯片组支持批处理芯片上的扫描
//        if (bluetoothAdapter.isOffloadedScanBatchingSupported()) {
//            //设置蓝牙LE扫描的报告延迟的时间（以毫秒为单位）
//            //设置为0以立即通知结果
//            builder.setReportDelay(1000);//设置延迟返回时间(毫秒值) [设置后onBatchScanResults运行]
//        }
        return builder.build();
    }
    //搜索回调
    private ScanCallback bluetoothScanCallBack = new ScanCallback() {
        @Override
        public void onScanResult(int callbackType, ScanResult result) {
            super.onScanResult(callbackType, result);
            BluetoothDevice device = result.getDevice();
            handler.post(()->{
                asyncScanResult(result);
            });
        }

        @Override
        public void onBatchScanResults(List<ScanResult> results) {
            super.onBatchScanResults(results);
            CaLogHelper.info(TAG,"[bluetoothScanCallBack]共搜索到"+results.size()+"个设备...");

            handler.post(()->{
                bluetoothDeviceModelList.clear();
                for (ScanResult result : results){
                    asyncScanResult(result);
                }
            });
        }

        @Override
        public void onScanFailed(int errorCode) {
            super.onScanFailed(errorCode);
            CaLogHelper.error(TAG,"[bluetoothScanCallBack]搜索设备失败...");
            isDiscovering = false;
        }
    };
    //同步新设备
    private void asyncScanResult(ScanResult scanResult){
        if(null != scanResultMap && null != scanResult){
            BluetoothDevice device = scanResult.getDevice();
            if(!scanResultMap.containsKey(device.getAddress())){
                scanResultMap.put(device.getAddress(),scanResult);
                BluetoothDeviceModel deviceModel = new BluetoothDeviceModel(scanResult.getDevice().getName(),scanResult.getDevice().getAddress());
                deviceModel.setBluetoothDevice(scanResult.getDevice());
                bluetoothDeviceModelList.add(deviceModel);
                CaLogHelper.warn(TAG,String.format("[bluetoothScanCallBack]搜索到新设备了(%s，%s,%d dB)...",device.getName(),device.getAddress(),scanResult.getRssi()));
                //发现新设备
                sendBroadcastToReceiver(BROADCAST_BLE_FOUND);
            }
        }
    }
    //蓝牙响应回调
    private BluetoothGattCallback bluetoothGattCallback = new BluetoothGattCallback() {
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            super.onConnectionStateChange(gatt, status, newState);
            CaLogHelper.info(TAG, "【BluetoothGattCallback】onConnectionStateChange");
            CaLogHelper.info(TAG, String.format("status=%d》newState=%d",status,newState));
            if(status == BluetoothGatt.GATT_SUCCESS){
                if (newState == BluetoothProfile.STATE_CONNECTED) {//连接成功
                    CaLogHelper.info(TAG, "【BluetoothGattCallback】蓝牙设备已连接成功...");
                    isConnecting = true;
                    //搜索设备服务集合Service
                    bluetoothGatt.discoverServices();
                } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {//断开连接
                    CaLogHelper.error(TAG, "【BluetoothGattCallback】蓝牙设备已断开连接...");
                    isConnecting = false;
                    doDisconnect();// 防止出现status 133
                }else{
                    //失败处理
                    CaLogHelper.error(TAG, "【BluetoothGattCallback】蓝牙设备连接失败...");
                    isConnecting = false;
                }
            }else{
                isConnecting = false;
                doDisconnect();// 防止出现status 133
                doConnect();
            }
        }

        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            super.onServicesDiscovered(gatt, status);
            CaLogHelper.info(TAG, "【BluetoothGattCallback】onServicesDiscovered");
            if (status == BluetoothGatt.GATT_SUCCESS) {
                CaLogHelper.info(TAG, "【BluetoothGattCallback】蓝牙设备已搜索到服务...");
                //组装服务
                List<BluetoothGattService> services = gatt.getServices();
                for(BluetoothGattService service:services){
                    //锁定服务UUID
                    if(service.getUuid().equals(bleServiceUuid)){
                        bluetoothGattService = service;
                        List<BluetoothGattCharacteristic> characteristics = service.getCharacteristics();
                        for (BluetoothGattCharacteristic characteristic : characteristics) {
                            //锁定服务特征UUID
                            if (characteristic.getUuid().equals(bleCharacteristicUuid)) {
                                // 订阅信息,否则接收不到数据
                                onCharacteristicNotification(characteristic, true);
                                break;
                            }
                        }
                        break;
                    }
                }
            }else{
                CaLogHelper.error(TAG, "【BluetoothGattCallback】onServicesDiscovered服务搜索失败...");
            }
        }

        @Override
        public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            CaLogHelper.info(TAG, "【BluetoothGattCallback】onCharacteristicRead");
//            super.onCharacteristicRead(gatt, characteristic, status);
            CaLogHelper.info(TAG,
                    String.format("向设备[%s]的特征[%s]读取数据，响应状态码[%d]...",gatt.getDevice().getAddress(),characteristic.getUuid().toString(),status));
            if (status == BluetoothGatt.GATT_SUCCESS) {
                CaLogHelper.info(TAG, "【BluetoothGattCallback】读取数据成功...");
            }
        }

        @Override
        public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            CaLogHelper.info(TAG, "【BluetoothGattCallback】onCharacteristicWrite");
//            super.onCharacteristicWrite(gatt, characteristic, status);
            CaLogHelper.info(TAG,
                    String.format("向设备[%s]的特征[%s]写入数据，响应状态码[%d]...",gatt.getDevice().getAddress(),characteristic.getUuid().toString(),status));
            if (status == BluetoothGatt.GATT_SUCCESS) {
                CaLogHelper.info(TAG, "【BluetoothGattCallback】写入数据成功...");
            }
        }

        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
            CaLogHelper.info(TAG, "【BluetoothGattCallback】onCharacteristicChanged");
//            super.onCharacteristicChanged(gatt, characteristic);
            String characteristicVal = CaConvertTool.bytes2HexString(characteristic.getValue());
            CaLogHelper.info(TAG,
                    String.format("监测设备[%s]的特征[%s]的响应数据，特征值：[%s]...",
                            gatt.getDevice().getAddress(),characteristic.getUuid().toString(),characteristicVal));
        }

    };
    //监听通知
    private boolean onCharacteristicNotification(BluetoothGattCharacteristic characteristic,boolean enabled){
        if(null == this.bluetoothGatt) return false;

        CaLogHelper.info(TAG, "【onCharacteristicNotification】蓝牙开启服务特征值通知监听...");
        this.bluetoothGattCharacteristic = characteristic;
        //组装描述符（默认第一个）
        BluetoothGattDescriptor descriptor = this.bluetoothGattCharacteristic.getDescriptors().get(0);
        if(null != descriptor){
            descriptor.setValue(enabled?BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE:BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
            bluetoothGatt.writeDescriptor(descriptor);
        }
        boolean result = bluetoothGatt.setCharacteristicNotification(this.bluetoothGattCharacteristic, enabled);
        //开始连接
        sendBroadcastToReceiver(BROADCAST_BLE_CONNECT);
        return result;
    }
    //监听指示
    private boolean onCharacteristicIndication(BluetoothGattCharacteristic characteristic){
        if(null == this.bluetoothGatt) return false;
        CaLogHelper.info(TAG, "【onCharacteristicIndication】蓝牙开启服务特征值指示监听...");
        //组装描述符（默认第一个）
        BluetoothGattDescriptor descriptor = characteristic.getDescriptors().get(0);
        if(null != descriptor){
            descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
            bluetoothGatt.writeDescriptor(descriptor);
        }
        return bluetoothGatt.setCharacteristicNotification(characteristic, true);
    }
    //适配器状态
    private boolean isHasAdapter(){
        return (null != bluetoothAdapter);
    }
}
